import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.table.AbstractTableModel;


public class SolverGUI {

	private JFrame frmMachineStateProblem;
	private JTextField txtFromState;
	private JTextField txtToState;
	private JTable table;
	private TransitionTable tTable;
	private JComboBox comboBox;
	private JScrollPane scrollPane;
	private SpringLayout springLayout;

	/**
	 * Create the application.
	 */
	public SolverGUI(TransitionTable t) {
		tTable = t;
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmMachineStateProblem = new JFrame();
		frmMachineStateProblem.setTitle("Machine State Problem - Solver");
		frmMachineStateProblem.setBounds(100, 100, 470, 300);
		frmMachineStateProblem.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		springLayout = new SpringLayout();
		frmMachineStateProblem.getContentPane().setLayout(springLayout);

		JLabel lblChooseAProblem = new JLabel("Choose a problem to solve:");
		springLayout.putConstraint(SpringLayout.NORTH, lblChooseAProblem, 10, SpringLayout.NORTH, frmMachineStateProblem.getContentPane());
		springLayout.putConstraint(SpringLayout.WEST, lblChooseAProblem, 10, SpringLayout.WEST, frmMachineStateProblem.getContentPane());
		frmMachineStateProblem.getContentPane().add(lblChooseAProblem);

		comboBox = new JComboBox();
		springLayout.putConstraint(SpringLayout.NORTH, comboBox, 10, SpringLayout.SOUTH, lblChooseAProblem);
		springLayout.putConstraint(SpringLayout.WEST, comboBox, 10, SpringLayout.WEST, frmMachineStateProblem.getContentPane());
		comboBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				int choice = ((JComboBox)arg0.getSource()).getSelectedIndex();
				if(txtFromState!=null || txtToState!=null)
					switch (choice) {
					case -1:
					case 0:		//Simple Control Problem
						txtFromState.setVisible(true);
						txtToState.setVisible(true);
						break;
					case 1:		//Terminal State Identification Problem
					case 2:		//Synchronizing Problem
					case 3:		//Initial State Problem
					default:
						txtFromState.setVisible(false);
						txtToState.setVisible(false);
						break;
					}
			}
		});
		comboBox.setModel(new DefaultComboBoxModel(new String[] {"Simple Control Problem", "Terminal State Identification Problem", "Synchronizing Problem", "Initial State Problem"}));
		comboBox.setSelectedIndex(0);
		frmMachineStateProblem.getContentPane().add(comboBox);

		txtFromState = new JTextField();
		springLayout.putConstraint(SpringLayout.NORTH, txtFromState, 0, SpringLayout.NORTH, comboBox);
		springLayout.putConstraint(SpringLayout.WEST, txtFromState, 10, SpringLayout.EAST, comboBox);
		springLayout.putConstraint(SpringLayout.SOUTH, comboBox, 0, SpringLayout.SOUTH, txtFromState);
		txtFromState.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent arg0) {
				txtFromState.setText("");
			}
		});
		txtFromState.setText("From state");
		//		txtFromState.setVisible(false);
		frmMachineStateProblem.getContentPane().add(txtFromState);
		txtFromState.setColumns(10);

		txtToState = new JTextField();
		springLayout.putConstraint(SpringLayout.WEST, txtToState, 10, SpringLayout.EAST, txtFromState);
		springLayout.putConstraint(SpringLayout.NORTH, txtToState, 0, SpringLayout.NORTH, comboBox);
		txtToState.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent arg0) {
				txtToState.setText("");
			}
		});
		txtToState.setText("To state");
		//		txtToState.setVisible(false);
		frmMachineStateProblem.getContentPane().add(txtToState);
		txtToState.setColumns(10);

		scrollPane = new JScrollPane(table);
		springLayout.putConstraint(SpringLayout.NORTH, scrollPane, 70, SpringLayout.NORTH, frmMachineStateProblem.getContentPane());
		springLayout.putConstraint(SpringLayout.WEST, scrollPane, 10, SpringLayout.WEST, frmMachineStateProblem.getContentPane());
		springLayout.putConstraint(SpringLayout.SOUTH, scrollPane, -10, SpringLayout.SOUTH, frmMachineStateProblem.getContentPane());
		springLayout.putConstraint(SpringLayout.EAST, scrollPane, -10, SpringLayout.EAST, frmMachineStateProblem.getContentPane());
		frmMachineStateProblem.getContentPane().add(scrollPane);

		JButton btnSolve = new JButton("Solve");
		springLayout.putConstraint(SpringLayout.EAST, txtToState, -10, SpringLayout.WEST, btnSolve);
		springLayout.putConstraint(SpringLayout.NORTH, btnSolve, 29, SpringLayout.NORTH, frmMachineStateProblem.getContentPane());
		springLayout.putConstraint(SpringLayout.EAST, comboBox, -191, SpringLayout.WEST, btnSolve);
		springLayout.putConstraint(SpringLayout.EAST, btnSolve, -10, SpringLayout.EAST, frmMachineStateProblem.getContentPane());
		btnSolve.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try{
				int choice = comboBox.getSelectedIndex();
				if(txtFromState!=null || txtToState!=null);
				switch (choice) {
				case -1:
				case 0:		//Simple Control Problem
					String from = txtFromState.getText();
					String to = txtToState.getText();
					if(from.length()!=1|| to.length()!=1||from.matches("[A-"+((char)('A'+Main.states-1))+"]")||to.matches("[A-"+((char)('A'+Main.states-1))+"]"))
						//TODO display error
						;
					displayTable(new String[][]{SolutionTree.createSolutionTree(Main.inputs, tTable).solveSCP(from.toUpperCase(), to.toUpperCase())}, new String[]{"Sequence"});
					txtFromState.setText("From state");
					txtFromState.setVisible(false);
					txtToState.setText("To state");
					txtToState.setVisible(false);
					break;
				case 1:		//Terminal State Identification Problem
					displayTable(SolutionTree.createSolutionTree(Main.inputs, tTable).solveTSIP(),new String[]{"Input Sq.","Terminal St.","Output"});
					break;
				case 2:		//Synchronizing Problem
					displayTable(SolutionTree.createSolutionTree(Main.inputs, tTable).solveSynchronize(),new String[]{"Sync. Seq.","Terminal State"});
					break;
				case 3:		//Initial State Problem
					displayTable(SolutionTree.createSolutionTree(Main.inputs, tTable).solveISIP(), new String[]{"Seq.","Initial St.","Curr. St.","Output"});
					break;
				default:
					txtFromState.setVisible(false);
					txtToState.setVisible(false);
					break;
				}
				}catch (Exception e){
					JOptionPane.showMessageDialog(frmMachineStateProblem,
						    "Couldn't solve problem.\nError: "+e.getCause(),
						    "Solving Error",
						    JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		frmMachineStateProblem.getContentPane().add(btnSolve);

		table = new JTable();

	}
	
	protected void displayTable(String[][] data, String[] header) {
		table = new JTable(new MyTableModel(data, header));
		frmMachineStateProblem.getContentPane().add(scrollPane);

		scrollPane.setViewportView(table);
		table.setFillsViewportHeight(true);

		scrollPane.setVisible(true);
	}

	public void setVisible() {
		frmMachineStateProblem.setVisible(true);
	}
	
	class MyTableModel extends AbstractTableModel {
		/**
		 * 
		 */
		private static final long serialVersionUID = -8430518479514938565L;
		String[][] data;
		String[] header;

		public MyTableModel(String[][] data, String[] header) {
			this.data = data;
			this.header = header;
		}

		public int getColumnCount() {
			return header.length;
		}

		public int getRowCount() {
			return data.length;
		}

		public String getColumnName(int col) {
			return header[col];
		}

		public Object getValueAt(int row, int col) {
			return data[row][col];
		}

		/*
		 * JTable uses this method to determine the default renderer/
		 * editor for each cell.  If we didn't implement this method,
		 * then the last column would contain text ("true"/"false"),
		 * rather than a check box.
		 */
		@SuppressWarnings({ "rawtypes", "unchecked" })
		public Class getColumnClass(int c) {
			return "".getClass();
		}

		/*
		 * Don't need to implement this method unless your table's
		 * editable.
		 */
		public boolean isCellEditable(int row, int col) {
			return false;
		}
	}
}
